//===- lib/MC/MCKifyAsmStreamer.cpp - Text Assembly Output ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCCodeView.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCRegister.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetRegistry.h"
#include <cctype>

#include "inc.h"

using namespace llvm;

namespace {

class MCKifyAsmStreamer final : public MCStreamer {
    std::unique_ptr<formatted_raw_ostream> OSOwner;
    formatted_raw_ostream& OS;
    const MCAsmInfo* MAI;
    std::unique_ptr<MCInstPrinter> InstPrinter;
    std::unique_ptr<MCAssembler> Assembler;

    SmallString<128> ExplicitCommentToEmit;
    SmallString<128> CommentToEmit;
    raw_svector_ostream CommentStream;
    raw_null_ostream NullStream;

    unsigned IsVerboseAsm : 1;
    unsigned ShowInst : 1;
    unsigned UseDwarfDirectory : 1;

    // void EmitRegisterName(int64_t Register);
    // void EmitCFIStartProcImpl(MCDwarfFrameInfo& Frame) override;
    // void EmitCFIEndProcImpl(MCDwarfFrameInfo& Frame) override;

public:
    MCKifyAsmStreamer(MCContext& Context, std::unique_ptr<formatted_raw_ostream> os,
        bool isVerboseAsm, bool useDwarfDirectory,
        MCInstPrinter* printer, std::unique_ptr<MCCodeEmitter> emitter,
        std::unique_ptr<MCAsmBackend> asmbackend, bool showInst)
        : MCStreamer(Context)
        , OSOwner(std::move(os))
        , OS(*OSOwner)
        , MAI(Context.getAsmInfo())
        , InstPrinter(printer)
        , Assembler(std::make_unique<MCAssembler>(
              Context, std::move(asmbackend), std::move(emitter),
              (asmbackend) ? asmbackend->createObjectWriter(NullStream)
                           : nullptr))
        , CommentStream(CommentToEmit)
        , IsVerboseAsm(isVerboseAsm)
        , ShowInst(showInst)
        , UseDwarfDirectory(useDwarfDirectory)
    {
        assert(InstPrinter);
        if (IsVerboseAsm)
            InstPrinter->setCommentStream(CommentStream);
        if (Assembler->getBackendPtr())
            setAllowAutoPadding(Assembler->getBackend().allowAutoPadding());
    }

    MCAssembler& getAssembler() { return *Assembler; }
    MCAssembler* getAssemblerPtr() override { return nullptr; }

    inline void EmitEOL()
    {
        // Dump Explicit Comments here.
        emitExplicitComments();
        // If we don't have any comments, just emit a \n.
        if (!IsVerboseAsm) {
            OS << '\n';
            return;
        }
        EmitCommentsAndEOL();
    }

    // void EmitSyntaxDirective() override;

    void EmitCommentsAndEOL();

    // /// Return true if this streamer supports verbose assembly at all.
    // bool isVerboseAsm() const override { return IsVerboseAsm; }

    // /// Do we support EmitRawText?
    // bool hasRawTextSupport() const override { return true; }

    // /// Add a comment that can be emitted to the generated .s file to make the
    // /// output of the compiler more readable. This only affects the MCKifyAsmStreamer
    // /// and only when verbose assembly output is enabled.
    // // void AddComment(const Twine& T, bool EOL = true) override;

    /// Add a comment showing the encoding of an instruction.
    void AddEncodingComment(const MCInst& Inst, const MCSubtargetInfo&);

    // /// Return a raw_ostream that comments can be written to.
    // /// Unlike AddComment, you are required to terminate comments with \n if you
    // /// use this method.
    raw_ostream& GetCommentOS() override
    {
        if (!IsVerboseAsm)
            return nulls(); // Discard comments unless in verbose asm mode.
        return CommentStream;
    }

    // void emitRawComment(const Twine& T, bool TabPrefix = true) override;

    // void addExplicitComment(const Twine& T) override;
    // void emitExplicitComments() override;

    /// Emit a blank line to a .s file to pretty it up.
    void AddBlankLine() override
    {
        EmitEOL();
    }

    /// @name MCStreamer Interface
    /// @{

    // void ChangeSection(MCSection* Section, const MCExpr* Subsection) override;

    // void emitELFSymverDirective(StringRef AliasName,
    //     const MCSymbol* Aliasee) override;

    // void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs& Args) override;
    // void EmitLabel(MCSymbol* Symbol, SMLoc Loc = SMLoc()) override;

    // void EmitAssemblerFlag(MCAssemblerFlag Flag) override;
    // void EmitLinkerOptions(ArrayRef<std::string> Options) override;
    // void EmitDataRegion(MCDataRegionType Kind) override;
    // void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor,
    //     unsigned Update, VersionTuple SDKVersion) override;
    // void EmitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor,
    //     unsigned Update, VersionTuple SDKVersion) override;
    // void EmitThumbFunc(MCSymbol* Func) override;

    // void EmitAssignment(MCSymbol* Symbol, const MCExpr* Value) override;
    // void EmitWeakReference(MCSymbol* Alias, const MCSymbol* Symbol) override;
    bool EmitSymbolAttribute(MCSymbol* Symbol, MCSymbolAttr Attribute) override{}

    // void EmitSymbolDesc(MCSymbol* Symbol, unsigned DescValue) override;
    // void BeginCOFFSymbolDef(const MCSymbol* Symbol) override;
    // void EmitCOFFSymbolStorageClass(int StorageClass) override;
    // void EmitCOFFSymbolType(int Type) override;
    // void EndCOFFSymbolDef() override;
    // void EmitCOFFSafeSEH(MCSymbol const* Symbol) override;
    // void EmitCOFFSymbolIndex(MCSymbol const* Symbol) override;
    // void EmitCOFFSectionIndex(MCSymbol const* Symbol) override;
    // void EmitCOFFSecRel32(MCSymbol const* Symbol, uint64_t Offset) override;
    // void EmitCOFFImgRel32(MCSymbol const* Symbol, int64_t Offset) override;
    // void EmitXCOFFLocalCommonSymbol(MCSymbol* LabelSym, uint64_t Size,
    //     MCSymbol* CsectSym,
    //     unsigned ByteAlign) override;
    // void emitELFSize(MCSymbol* Symbol, const MCExpr* Value) override;
    void EmitCommonSymbol(MCSymbol* Symbol, uint64_t Size,
        unsigned ByteAlignment) override{}

    // /// Emit a local common (.lcomm) symbol.
    // ///
    // /// @param Symbol - The common symbol to emit.
    // /// @param Size - The size of the common symbol.
    // /// @param ByteAlignment - The alignment of the common symbol in bytes.
    // void EmitLocalCommonSymbol(MCSymbol* Symbol, uint64_t Size,
    //     unsigned ByteAlignment) override;

    void EmitZerofill(MCSection* Section, MCSymbol* Symbol = nullptr,
        uint64_t Size = 0, unsigned ByteAlignment = 0,
        SMLoc Loc = SMLoc()) override{}

    // void EmitTBSSSymbol(MCSection* Section, MCSymbol* Symbol, uint64_t Size,
    //     unsigned ByteAlignment = 0) override;

    // void EmitBinaryData(StringRef Data) override;

    // void EmitBytes(StringRef Data) override;

    // void EmitValueImpl(const MCExpr* Value, unsigned Size,
    //     SMLoc Loc = SMLoc()) override;
    // void EmitIntValue(uint64_t Value, unsigned Size) override;
    // void EmitIntValueInHex(uint64_t Value, unsigned Size) override;

    // void EmitULEB128Value(const MCExpr* Value) override;

    // void EmitSLEB128Value(const MCExpr* Value) override;

    // void EmitDTPRel32Value(const MCExpr* Value) override;
    // void EmitDTPRel64Value(const MCExpr* Value) override;
    // void EmitTPRel32Value(const MCExpr* Value) override;
    // void EmitTPRel64Value(const MCExpr* Value) override;

    // void EmitGPRel64Value(const MCExpr* Value) override;

    // void EmitGPRel32Value(const MCExpr* Value) override;

    // void emitFill(const MCExpr& NumBytes, uint64_t FillValue,
    //     SMLoc Loc = SMLoc()) override;

    // void emitFill(const MCExpr& NumValues, int64_t Size, int64_t Expr,
    //     SMLoc Loc = SMLoc()) override;

    // void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
    //     unsigned ValueSize = 1,
    //     unsigned MaxBytesToEmit = 0) override;

    // void EmitCodeAlignment(unsigned ByteAlignment,
    //     unsigned MaxBytesToEmit = 0) override;

    // void emitValueToOffset(const MCExpr* Offset,
    //     unsigned char Value,
    //     SMLoc Loc) override;

    // void EmitFileDirective(StringRef Filename) override;
    // Expected<unsigned> tryEmitDwarfFileDirective(unsigned FileNo,
    //     StringRef Directory,
    //     StringRef Filename,
    //     Optional<MD5::MD5Result> Checksum = None,
    //     Optional<StringRef> Source = None,
    //     unsigned CUID = 0) override;
    // void emitDwarfFile0Directive(StringRef Directory, StringRef Filename,
    //     Optional<MD5::MD5Result> Checksum,
    //     Optional<StringRef> Source,
    //     unsigned CUID = 0) override;
    // void EmitDwarfLocDirective(unsigned FileNo, unsigned Line,
    //     unsigned Column, unsigned Flags,
    //     unsigned Isa, unsigned Discriminator,
    //     StringRef FileName) override;
    // MCSymbol* getDwarfLineTableSymbol(unsigned CUID) override;

    // bool EmitCVFileDirective(unsigned FileNo, StringRef Filename,
    //     ArrayRef<uint8_t> Checksum,
    //     unsigned ChecksumKind) override;
    // bool EmitCVFuncIdDirective(unsigned FuncId) override;
    // bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
    //     unsigned IAFile, unsigned IALine,
    //     unsigned IACol, SMLoc Loc) override;
    // void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
    //     unsigned Column, bool PrologueEnd, bool IsStmt,
    //     StringRef FileName, SMLoc Loc) override;
    // void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol* FnStart,
    //     const MCSymbol* FnEnd) override;
    // void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
    //     unsigned SourceFileId,
    //     unsigned SourceLineNum,
    //     const MCSymbol* FnStartSym,
    //     const MCSymbol* FnEndSym) override;

    // void PrintCVDefRangePrefix(
    //     ArrayRef<std::pair<const MCSymbol*, const MCSymbol*>> Ranges);

    // void EmitCVDefRangeDirective(
    //     ArrayRef<std::pair<const MCSymbol*, const MCSymbol*>> Ranges,
    //     codeview::DefRangeRegisterRelHeader DRHdr) override;

    // void EmitCVDefRangeDirective(
    //     ArrayRef<std::pair<const MCSymbol*, const MCSymbol*>> Ranges,
    //     codeview::DefRangeSubfieldRegisterHeader DRHdr) override;

    // void EmitCVDefRangeDirective(
    //     ArrayRef<std::pair<const MCSymbol*, const MCSymbol*>> Ranges,
    //     codeview::DefRangeRegisterHeader DRHdr) override;

    // void EmitCVDefRangeDirective(
    //     ArrayRef<std::pair<const MCSymbol*, const MCSymbol*>> Ranges,
    //     codeview::DefRangeFramePointerRelHeader DRHdr) override;

    // void EmitCVStringTableDirective() override;
    // void EmitCVFileChecksumsDirective() override;
    // void EmitCVFileChecksumOffsetDirective(unsigned FileNo) override;
    // void EmitCVFPOData(const MCSymbol* ProcSym, SMLoc L) override;

    // void EmitIdent(StringRef IdentString) override;
    // void EmitCFIBKeyFrame() override;
    // void EmitCFISections(bool EH, bool Debug) override;
    // void EmitCFIDefCfa(int64_t Register, int64_t Offset) override;
    // void EmitCFIDefCfaOffset(int64_t Offset) override;
    // void EmitCFIDefCfaRegister(int64_t Register) override;
    // void EmitCFIOffset(int64_t Register, int64_t Offset) override;
    // void EmitCFIPersonality(const MCSymbol* Sym, unsigned Encoding) override;
    // void EmitCFILsda(const MCSymbol* Sym, unsigned Encoding) override;
    // void EmitCFIRememberState() override;
    // void EmitCFIRestoreState() override;
    // void EmitCFIRestore(int64_t Register) override;
    // void EmitCFISameValue(int64_t Register) override;
    // void EmitCFIRelOffset(int64_t Register, int64_t Offset) override;
    // void EmitCFIAdjustCfaOffset(int64_t Adjustment) override;
    // void EmitCFIEscape(StringRef Values) override;
    // void EmitCFIGnuArgsSize(int64_t Size) override;
    // void EmitCFISignalFrame() override;
    // void EmitCFIUndefined(int64_t Register) override;
    // void EmitCFIRegister(int64_t Register1, int64_t Register2) override;
    // void EmitCFIWindowSave() override;
    // void EmitCFINegateRAState() override;
    // void EmitCFIReturnColumn(int64_t Register) override;

    // void EmitWinCFIStartProc(const MCSymbol* Symbol, SMLoc Loc) override;
    // void EmitWinCFIEndProc(SMLoc Loc) override;
    // void EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) override;
    // void EmitWinCFIStartChained(SMLoc Loc) override;
    // void EmitWinCFIEndChained(SMLoc Loc) override;
    // void EmitWinCFIPushReg(MCRegister Register, SMLoc Loc) override;
    // void EmitWinCFISetFrame(MCRegister Register, unsigned Offset,
    //     SMLoc Loc) override;
    // void EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) override;
    // void EmitWinCFISaveReg(MCRegister Register, unsigned Offset,
    //     SMLoc Loc) override;
    // void EmitWinCFISaveXMM(MCRegister Register, unsigned Offset,
    //     SMLoc Loc) override;
    // void EmitWinCFIPushFrame(bool Code, SMLoc Loc) override;
    // void EmitWinCFIEndProlog(SMLoc Loc) override;

    // void EmitWinEHHandler(const MCSymbol* Sym, bool Unwind, bool Except,
    //     SMLoc Loc) override;
    // void EmitWinEHHandlerData(SMLoc Loc) override;

    // void emitCGProfileEntry(const MCSymbolRefExpr* From,
    //     const MCSymbolRefExpr* To, uint64_t Count) override;

    void EmitInstruction(const MCInst& Inst, const MCSubtargetInfo& STI) override;

    // void EmitBundleAlignMode(unsigned AlignPow2) override;
    // void EmitBundleLock(bool AlignToEnd) override;
    // void EmitBundleUnlock() override;

    // bool EmitRelocDirective(const MCExpr& Offset, StringRef Name,
    //     const MCExpr* Expr, SMLoc Loc,
    //     const MCSubtargetInfo& STI) override;

    // void EmitAddrsig() override;
    // void EmitAddrsigSym(const MCSymbol* Sym) override;

    // /// If this file is backed by an assembly streamer, this dumps the specified
    // /// string in the output .s file. This capability is indicated by the
    // /// hasRawTextSupport() predicate.
    // void EmitRawTextImpl(StringRef String) override;

    // void FinishImpl() override;
};

} // end anonymous namespace.

void MCKifyAsmStreamer::EmitCommentsAndEOL()
{
    if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) {
        OS << '\n';
        return;
    }

    StringRef Comments = CommentToEmit;

    assert(Comments.back() == '\n' && "Comment array not newline terminated");
    do {
        // Emit a line of comments.
        OS.PadToColumn(MAI->getCommentColumn());
        size_t Position = Comments.find('\n');
        OS << MAI->getCommentString() << ' ' << Comments.substr(0, Position) << '\n';

        Comments = Comments.substr(Position + 1);
    } while (!Comments.empty());

    CommentToEmit.clear();
}

// void MCKifyAsmStreamer::EmitThumbFunc(MCSymbol* Func)
// {
//     // This needs to emit to a temporary string to get properly quoted
//     // MCSymbols when they have spaces in them.
//     OS << "\t.thumb_func";
//     // Only Mach-O hasSubsectionsViaSymbols()
//     if (MAI->hasSubsectionsViaSymbols()) {
//         OS << '\t';
//         Func->print(OS, MAI);
//     }
//     EmitEOL();
// }

static inline char toOctal(int X) { return (X & 7) + '0'; }

static void PrintQuotedString(StringRef Data, raw_ostream& OS)
{
    OS << '"';

    for (unsigned i = 0, e = Data.size(); i != e; ++i) {
        unsigned char C = Data[i];
        if (C == '"' || C == '\\') {
            OS << '\\' << (char)C;
            continue;
        }

        if (isPrint((unsigned char)C)) {
            OS << (char)C;
            continue;
        }

        switch (C) {
        case '\b':
            OS << "\\b";
            break;
        case '\f':
            OS << "\\f";
            break;
        case '\n':
            OS << "\\n";
            break;
        case '\r':
            OS << "\\r";
            break;
        case '\t':
            OS << "\\t";
            break;
        default:
            OS << '\\';
            OS << toOctal(C >> 6);
            OS << toOctal(C >> 3);
            OS << toOctal(C >> 0);
            break;
        }
    }

    OS << '"';
}


void MCKifyAsmStreamer::AddEncodingComment(const MCInst& Inst,
    const MCSubtargetInfo& STI)
{
    raw_ostream& OS = GetCommentOS();
    SmallString<256> Code;
    SmallVector<MCFixup, 4> Fixups;
    raw_svector_ostream VecOS(Code);

    // If we have no code emitter, don't emit code.
    if (!getAssembler().getEmitterPtr())
        return;

    getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);

    // If we are showing fixups, create symbolic markers in the encoded
    // representation. We do this by making a per-bit map to the fixup item index,
    // then trying to display it as nicely as possible.
    SmallVector<uint8_t, 64> FixupMap;
    FixupMap.resize(Code.size() * 8);
    for (unsigned i = 0, e = Code.size() * 8; i != e; ++i)
        FixupMap[i] = 0;

    for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
        MCFixup& F = Fixups[i];
        const MCFixupKindInfo& Info = getAssembler().getBackend().getFixupKindInfo(F.getKind());
        for (unsigned j = 0; j != Info.TargetSize; ++j) {
            unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j;
            assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
            FixupMap[Index] = 1 + i;
        }
    }

    // FIXME: Note the fixup comments for Thumb2 are completely bogus since the
    // high order halfword of a 32-bit Thumb2 instruction is emitted first.
    OS << "encoding: [";
    for (unsigned i = 0, e = Code.size(); i != e; ++i) {
        if (i)
            OS << ',';

        // See if all bits are the same map entry.
        uint8_t MapEntry = FixupMap[i * 8 + 0];
        for (unsigned j = 1; j != 8; ++j) {
            if (FixupMap[i * 8 + j] == MapEntry)
                continue;

            MapEntry = uint8_t(~0U);
            break;
        }

        if (MapEntry != uint8_t(~0U)) {
            if (MapEntry == 0) {
                OS << format("0x%02x", uint8_t(Code[i]));
            } else {
                if (Code[i]) {
                    // FIXME: Some of the 8 bits require fix up.
                    OS << format("0x%02x", uint8_t(Code[i])) << '\''
                       << char('A' + MapEntry - 1) << '\'';
                } else
                    OS << char('A' + MapEntry - 1);
            }
        } else {
            // Otherwise, write out in binary.
            OS << "0b";
            for (unsigned j = 8; j--;) {
                unsigned Bit = (Code[i] >> j) & 1;

                unsigned FixupBit;
                if (MAI->isLittleEndian())
                    FixupBit = i * 8 + j;
                else
                    FixupBit = i * 8 + (7 - j);

                if (uint8_t MapEntry = FixupMap[FixupBit]) {
                    assert(Bit == 0 && "Encoder wrote into fixed up bit!");
                    OS << char('A' + MapEntry - 1);
                } else
                    OS << Bit;
            }
        }
    }
    OS << "]\n";

    for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
        MCFixup& F = Fixups[i];
        const MCFixupKindInfo& Info = getAssembler().getBackend().getFixupKindInfo(F.getKind());
        OS << "  fixup " << char('A' + i) << " - "
           << "offset: " << F.getOffset()
           << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n";
    }
}

void MCKifyAsmStreamer::EmitInstruction(const MCInst& Inst,
    const MCSubtargetInfo& STI)
{
    assert(getCurrentSectionOnly() && "Cannot emit contents before setting section!");

    // Show the encoding in a comment if we have a code emitter.
    AddEncodingComment(Inst, STI);

    // // Show the MCInst if enabled.
    // if (ShowInst) {
    //     Inst.dump_pretty(GetCommentOS(), InstPrinter.get(), "\n ");
    //     GetCommentOS() << "\n";
    // }

    if (getTargetStreamer())
        getTargetStreamer()->prettyPrintAsm(*InstPrinter, 0, Inst, STI, OS);
    else
        InstPrinter->printInst(&Inst, 0, "", STI, OS);

    // StringRef Comments = CommentToEmit;
    // if (Comments.size() && Comments.back() != '\n')
    //     GetCommentOS() << "\n";

    EmitEOL();
}

#include "one-inst-asm-streamer-split.cc"

llvm::MCStreamer* llvm::kifycreateAsmStreamer(MCContext& Context,
    std::unique_ptr<formatted_raw_ostream> OS,
    bool isVerboseAsm, bool useDwarfDirectory,
    MCInstPrinter* IP,
    std::unique_ptr<MCCodeEmitter>&& CE,
    std::unique_ptr<MCAsmBackend>&& MAB,
    bool ShowInst)
{
    return new MCKifyAsmStreamer(Context, std::move(OS), isVerboseAsm,
        useDwarfDirectory, IP, std::move(CE), std::move(MAB),
        ShowInst);
}

llvm::MCStreamer* llvm::kify_nncreateAsmStreamer(MCContext& Ctx,
    std::unique_ptr<formatted_raw_ostream> OS,
    bool IsVerboseAsm, bool UseDwarfDirectory,
    MCInstPrinter* InstPrint,
    std::unique_ptr<MCCodeEmitter>&& CE,
    std::unique_ptr<MCAsmBackend>&& TAB,
    bool ShowInst, const Target* TheTarget)
{
    formatted_raw_ostream& OSRef = *OS;
    MCStreamer* S = kifycreateAsmStreamer(
        Ctx, std::move(OS), IsVerboseAsm, UseDwarfDirectory, InstPrint,
        std::move(CE), std::move(TAB), ShowInst);
    TheTarget->createAsmTargetStreamer(*S, OSRef, InstPrint, IsVerboseAsm);
    return S;
}
